package com.jvmoutofmemory.platform.pushutil.service;

import com.jvmoutofmemory.platform.pushutil.constants.PushJobMethod;
import com.jvmoutofmemory.platform.pushutil.constants.PushJobParamType;
import com.jvmoutofmemory.platform.pushutil.dto.PushResult;
import com.jvmoutofmemory.platform.pushutil.entity.PushJob;
import com.jvmoutofmemory.platform.pushutil.response.PushRequestSender;
import com.jvmoutofmemory.platform.pushutil.response.PushResponseListener;
import com.jvmoutofmemory.platform.pushutil.response.PushResponseParser;
import com.jvmoutofmemory.platform.pushutil.util.UUIDUtil;
import com.jvmoutofmemory.platform.pushutil.util.WebUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author adam
 * @date 2022-06-02
 */
@Slf4j
public class PushComponent implements InitializingBean, ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Autowired
    private List<PushResponseParser> pushResponseParsers;
    private Map<String, PushResponseParser> map = new HashMap<>();
    private Map<String, PushRequestSender> senderHashMap = new HashMap<>();

    public PushResponseParser getResponseParser(String type) {
        return map.get(type);
    }

    /**
     * 执行推送
     */
    public PushResult push(PushJob pushJob) {
        // 根据pushjob的系统类型调用对应实现类，解析push结果
        PushResponseParser pushResponseParser = getResponseParser(pushJob.getSysType());
        if (pushResponseParser == null) {
            return new PushResult(false, "未找到对应pushResponseParser实现，"+ pushJob.getSysType());
        }

        pushJob.setPushRid(StringUtils.isEmpty(MDC.get("traceId")) ? UUIDUtil.uuid() : MDC.get("traceId"));

        boolean success = false;
        String response = null;
        try {
            response = send(pushJob);
            if (StringUtils.isEmpty(response)) {
                return new PushResult(false, "推送任务返回结果为空");
            }

            success = pushResponseParser.isSuccess(response);
            return new PushResult(success, null, response);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return new PushResult(success, e.getMessage());
        }
    }

    @SuppressWarnings({"rawtypes"})
    public PushResponseListener getPushResponseListener(PushJob pushJob) {
        PushResponseListener listener = null;
        if (!StringUtils.isEmpty(pushJob.getListener())) {
            try {
                Class clazz = Class.forName(pushJob.getListener());
                listener = (PushResponseListener) applicationContext.getBean(clazz);
            } catch (Exception e) {
                log.error("未找到对应的监听: {}", pushJob.getListener());
                log.error(e.getMessage(), e);
            }
        }
        return listener;
    }

    //发送请求
    private String send(PushJob pushJob) throws Exception {
        PushRequestSender requestSender = senderHashMap.get(pushJob.getSysType());
        if (requestSender != null) {
            return requestSender.request(pushJob);
        }

        Short method = pushJob.getMethod();
        if (null == method){
            throw new RuntimeException("推送任务执行失败：该任务没有设置请求方式");
        }

        String url = pushJob.getUrl();
        String param = pushJob.getParam();
        if (method.equals(PushJobMethod.GET.getCode())) {
            return WebUtil.get(url, param);
        } else if (method.equals(PushJobMethod.POST.getCode())) {
            Short paramType = pushJob.getParamType();
            if (null == paramType){
                throw new RuntimeException("推送任务执行失败：该任务没有设置请求参数类型");
            }
            // json
            if (paramType.equals(PushJobParamType.JSON_DATA.getCode()))
                return WebUtil.postJson(url, param);
                // form-data
            else if (paramType.equals(PushJobParamType.FORM_DATA.getCode()))
                return WebUtil.postForm(url, param);
            else
                throw new RuntimeException("推送任务执行失败：未知的请求参数类型");
        } else {
            throw new RuntimeException(String.format("推送任务执行失败：未知的请求方式： %s", method));
        }
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        for (PushResponseParser pushResponseParser : pushResponseParsers) {
            String[] types = pushResponseParser.supportSystem();
            for (String type : types) {
                map.put(type, pushResponseParser);
            }
        }

        try {
            Map<String, PushRequestSender> senderMap = applicationContext.getBeansOfType(PushRequestSender.class);
            if (!CollectionUtils.isEmpty(senderMap)) {
                senderMap.forEach((k, v) -> {
                    String[] sysTypes = v.supportSystem();
                    for (String sysType : sysTypes) {
                        senderHashMap.put(sysType, v);
                    }
                });
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
